package com.msh.artascope.devcloud.service.service.impl;


import com.msh.artascope.devcloud.client.po.*;
import com.msh.artascope.devcloud.client.qo.EnvQo;
import com.msh.artascope.devcloud.client.qo.ModuleQo;
import com.msh.artascope.devcloud.client.qo.ProductQo;
import com.msh.artascope.devcloud.service.dao.ProjectDao;
import com.msh.artascope.devcloud.service.interfaces.IGitAccess;
import com.msh.artascope.devcloud.service.model.page.ModuleBuildRunPageVo;
import com.msh.artascope.devcloud.service.model.page.ModuleListBuildRunPageVo;
import com.msh.artascope.devcloud.service.model.page.ProjectListPageQo;
import com.msh.artascope.devcloud.service.model.page.ProjectListPageVo;
import com.msh.artascope.devcloud.service.model.query.ProjectQueryVo;
import com.msh.artascope.devcloud.service.model.vo.ProjectVo;
import com.msh.artascope.devcloud.service.service.*;
import com.msh.artascope.devcloud.service.wrapper.GitWrapper;
import com.msh.artascope.devcloud.service.wrapper.JenkinsWrapper;
import com.msh.frame.client.base.SortBy;
import com.msh.frame.client.base.TenantBaseServiceImpl;
import com.msh.frame.client.common.ITreeConstructor;
import com.msh.frame.client.define.ColumnDef;
import com.msh.frame.client.exception.BizException;

import javax.annotation.Resource;

import com.msh.frame.client.model.TreeVo;
import com.msh.frame.interfaces.IdGenerateable;
import com.msh.artascope.devcloud.client.qo.ProjectQo;
import com.msh.frame.client.common.Result;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author shihu
 * @mail m-sh@qq.com
 */
@Service
@Slf4j
public class ProjectServiceImpl extends TenantBaseServiceImpl<ProjectPo,ProjectQo> implements ProjectService {

  @Resource
  private ProjectDao projectDao;

  @Resource
  private IdGenerateable idGenerateable;

  @Autowired
  private ModuleService moduleService;

  @Autowired
  private GitWrapper gitWrapper;

  @Autowired
  private IGitAccess gitAccess;

  @Autowired
  private JenkinsWrapper jenkinsWrapper;

  @Autowired
  private GitlabConfigService gitlabConfigService;

  @Autowired
  private JenkinsConfigService jenkinsConfigService;

  @Autowired
  private EnvService envService;

  @Autowired
  @Lazy
  private ProductService productService;

  @Override
  public long insert(ProjectPo param) {
    Long envId = param.getEnvId();
    Long tenantId = param.getTenantId();
    EnvPo envPo = envService.get(envId, tenantId);
    BizException.doThrowIfNull("无法获取环境信息", envPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少jenkins配置", jenkinsConfigPo);
    return insert(param, jenkinsConfigPo, envPo);
  }

  @Override
  public long insert(ProjectPo param, JenkinsConfigPo jenkinsConfigPo, EnvPo envPo){
    param.setId(idGenerateable.getUniqueId());
    ProjectPo projectPo = this
            .listOne(new ProjectQo().setEnvId(envPo.getId()).setName(param.getName()));
    BizException.doThrowIfTrue("该环境下项目已存在", null != projectPo);
    long insert = super.insert(param);
    jenkinsWrapper.createJob(jenkinsConfigPo, envPo.getNamespace(), param.getName());
    return insert;
  }

  @Override
  public int insertCollection(Collection<ProjectPo> param) {
    param.stream().forEach(p->p.setId(idGenerateable.getUniqueId()));
    return super.insertCollection(param);
  }


  @Override
  public ProjectPo getByModuleId(Long moduleId, Long tenantId) {
    ModulePo modulePo = moduleService.get(moduleId, tenantId);
    BizException.doThrowIfNull("无法获取模块信息", modulePo);
    ProjectPo projectPo = get(modulePo.getProjectId(), tenantId);
    BizException.doThrowIfNull("无法获取项目信息", modulePo);
    return projectPo;
  }


  @Override
  @Transactional(rollbackFor = Exception.class)
  public int delete(Long id, Long tenantId) {
    ModulePo modulePo = moduleService.listOne(new ModuleQo().setProjectId(id).setTenantId(tenantId));
    BizException.doThrowIfTrue("请先删除制品", null != modulePo);
    ProjectPo projectPo = this.get(id, tenantId);
    if(null == projectPo){
      return 0;
    }
    EnvPo envPo = envService.get(projectPo.getEnvId(), tenantId);
    BizException.doThrowIfNull("无法获取环境信息", envPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(projectPo.getEnvId(), projectPo.getTenantId());
    BizException.doThrowIfNull("缺少jenkins配置", jenkinsConfigPo);
    int delete = super.delete(id, tenantId);
    jenkinsWrapper.removeJob(jenkinsConfigPo, envPo.getNamespace(), projectPo.getName());
    return delete;
  }



// ----------前端vo处理-------------------------------------------------------

  private ProjectVo toVo(ProjectPo po){
    ProjectVo vo = po.convert(ProjectVo.class);
    return vo;
  }

  private List<ProjectVo> toVoList(List<ProjectPo> list){
    if(CollectionUtils.isEmpty(list)){
      return Collections.emptyList();
    }

    return list.stream().map(po->{
      return toVo(po);
    }).collect(Collectors.toList());
  }

  @Override
  public ProjectVo getVo(Long id, Long tenantId) {
    ProjectPo po = this.get(id, tenantId);
    if(null == po){
      return null;
    }
    ProjectVo vo = toVo(po);

    return vo;
  }

  @Override
  public List<ProjectVo> listVo(ProjectQueryVo q){
    ProjectQo qo = q.convert(ProjectQo.class);
    List<ProjectPo> poList = this.list(qo);
    List<ProjectVo> voList = toVoList(poList);

    return voList;
  }

  @Override
  public Result<List<ProjectVo>> pageVo(ProjectQueryVo param) {
    ProjectQo qo = param.convert(ProjectQo.class);
    int count = this.count(qo);
    if (0 == count) {
      return Result.successReturn(Collections.<ProjectVo>emptyList()).setCount(count);
    }
    List<ProjectPo> poList = this.list(qo);
    List<ProjectVo> voList = toVoList(poList);

    return Result.successReturn(voList).setCount(count);
  }

  @Override
  public ProjectListPageVo projectListPageVoByModuleId(Long moduleId, Long tenantId) {
    ModulePo modulePo = moduleService.get(moduleId, tenantId);
    BizException.doThrowIfNull("模块信息不存在", modulePo);
    ProjectPo projectPo = get(modulePo.getProjectId(), tenantId);
    BizException.doThrowIfNull("项目信息不存在", modulePo);
    return projectListPageVo(projectPo.getProductId(), projectPo.getEnvId(), projectPo, modulePo);
  }

  @Override
  public ProjectListPageVo projectListPageVo(ProjectListPageQo projectListPageQo, Long tenantId) {
    Long productId = projectListPageQo.getProductId();
    Long envId = projectListPageQo.getEnvId();
    Long projectId = projectListPageQo.getProjectId();
    Long moduleId = projectListPageQo.getModuleId();
    String projectName = projectListPageQo.getProjectName();
    String moduleName = projectListPageQo.getModuleName();
    if(null != projectId || null != moduleId){
      return projectListPageVo(envId, projectId, moduleId, tenantId);
    }
    if(!StringUtils.isEmpty(projectName) || !StringUtils.isEmpty(moduleName)){
      return projectListPageVo(productId, envId, projectName, moduleName, tenantId);
    }
    return projectListPageVo(productId, envId, (ProjectPo) null, null);
  }

  /**
   * 通过名字查询信息
   * @param productId
   * @param envId
   * @param projectName
   * @param moduleName
   * @return
   */
  private ProjectListPageVo projectListPageVo(Long productId, Long envId, String projectName, String moduleName, Long tenantId) {
    ModulePo modulePo = null;
    ProjectPo projectPo = null;
    if(!StringUtils.isEmpty(moduleName)){
      modulePo = moduleService.listOne(new ModuleQo().setName(moduleName).setEnvId(envId));
      if(null != modulePo){
        projectPo = get(modulePo.getProjectId(), tenantId);
      }
    }else if(!StringUtils.isEmpty(projectName)){
      projectPo = listOne(new ProjectQo().setName(projectName).setEnvId(envId));
      if(null != projectPo){
        modulePo = moduleService.listOne(new ModuleQo().setEnvId(envId).setProjectId(projectPo.getId()));
      }
    }
    if(null != projectPo){
      productId = projectPo.getProductId();
    }
    return this.projectListPageVo(productId, envId, projectPo, modulePo);
  }

  /**
   * 通过id 查询信息
   * @param envId
   * @param projectId
   * @param moduleId
   * @return
   */
  private ProjectListPageVo projectListPageVo(Long envId, Long projectId, Long moduleId, Long tenantId) {
    ModulePo modulePo = null;
    ProjectPo projectPo = null;
    if(null != moduleId){
      modulePo = moduleService.get(moduleId, tenantId);
      if(null == modulePo){
        return projectListPageVo(envId, projectId, null, tenantId);
      }
      projectPo = get(modulePo.getProjectId(), tenantId);
      if(null == projectPo){
        return projectListPageVo(envId, null, null, tenantId);
      }
    }else if(null != projectId){
      projectPo = get(projectId, tenantId);
      BizException.doThrowIfNull("未获取到项目信息", projectPo);
      modulePo = moduleService.listOne(new ModuleQo().setProjectId(projectId).setEnvId(envId));
    }
    BizException.doThrowIfNull("项目信息环境不符", !projectPo.getEnvId().equals(envId));
    return this.projectListPageVo(projectPo.getProductId(), envId, projectPo, modulePo);
  }

  private ProjectListPageVo projectListPageVo(Long productId, Long envId, ProjectPo projectPo, ModulePo modulePo) {
    if(null == productId){
      return emptyProjectListPageVo();
    }
    List<ProjectPo> list = this.list(new ProjectQo().setProductId(productId).setEnvId(envId).setSortBy(
        SortBy.asc(ColumnDef.NAME)));
    if(CollectionUtils.isEmpty(list)){
      return emptyProjectListPageVo();
    }
    ProjectListPageVo projectListPageVo = new ProjectListPageVo();
    projectListPageVo.setProjectList(list);
    if(null == projectPo){
      projectPo = list.get(0);
    }
    projectListPageVo.setProject(projectPo);

    ModuleListBuildRunPageVo moduleListBuildRunPageVo = moduleService
        .moduleListBuildRunPageVo(projectPo.getId(), modulePo);
    projectListPageVo.setModuleListBuildRun(moduleListBuildRunPageVo);

    return projectListPageVo;
  }

  private ProjectListPageVo emptyProjectListPageVo(){
    ProjectListPageVo projectListPageVo = new ProjectListPageVo();
    projectListPageVo.setProjectList(Collections.emptyList());
    ModuleListBuildRunPageVo moduleListBuildRunPageVo = new ModuleListBuildRunPageVo();
    moduleListBuildRunPageVo.setModuleList(Collections.emptyList());
    moduleListBuildRunPageVo.setModuleBuildRun(new ModuleBuildRunPageVo());
    projectListPageVo.setModuleListBuildRun(moduleListBuildRunPageVo);
    return projectListPageVo;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public ProjectVo insertVo(ProjectVo projectVo) {
    GitlabConfigPo gitlabConfigPo = gitlabConfigService
        .getByEnvId(projectVo.getEnvId(), projectVo.getTenantId());
    BizException.doThrowIfNull("缺少git配置", gitlabConfigPo);
    String gitUrl = projectVo.getGitUrl();
    String targetData = gitUrl.split(":")[1];
    String nameWithNamespace = targetData.substring(0,targetData.lastIndexOf("."));
    String gitProjectName = nameWithNamespace.substring(nameWithNamespace.lastIndexOf("/")+1);
    projectVo.setName(gitProjectName);
    Long gitId = gitWrapper.getProjectId(gitlabConfigPo, gitUrl);
    BizException.doThrowIfNull("请确认地址是否正确", gitId);
    BizException.doThrowIfTrue("没有项目权限", !gitAccess.access(gitId));
    projectVo.setGitId(gitId);

    this.insert(projectVo);
    return projectVo;
  }

  @Override
  public List<EnvPo> copyEnableEnv(String projectName, Long tenantId) {
    List<EnvPo> list = envService.list(new EnvQo().setTenantId(tenantId));
    ProjectQo projectQo = new ProjectQo();
    projectQo.setName(projectName);
    Set<Long> set = list(projectQo).stream().map(ProjectPo::getEnvId).collect(Collectors.toSet());
    return list.stream()
        .filter(e-> !set.contains(e.getId()))
        .collect(Collectors.toList());
  }

  @Override
  public ProjectPo copy(Long id, Long envId, Long tenantId) {
    ProjectPo projectPo = get(id, tenantId);
    return copy(projectPo, envId);
  }

  @Override
  public ProjectPo copy(ProjectPo source, Long envId) {
    BizException.doThrowIfNull("未获取到项目信息", source);
    source.setEnvId(envId);
    source.setCreateTime(null);
    source.setUpdateTime(null);
    source.setUpdateVersion(1);
    insert(source);
    return source;
  }

  @Override
  public ProjectPo copy(ProjectPo source, JenkinsConfigPo jenkinsConfigPo, EnvPo envPo) {
    BizException.doThrowIfNull("未获取到项目信息", source);
    source.setEnvId(envPo.getId());
    source.setCreateTime(null);
    source.setUpdateTime(null);
    source.setUpdateVersion(1);
    insert(source, jenkinsConfigPo, envPo);
    return source;
  }


  @Override
  public List<TreeVo> listProductProjectTree(ProjectQueryVo q) {
    List<ProjectPo> projectPoList = list(q);
    if(CollectionUtils.isEmpty(projectPoList)){
      return Collections.emptyList();
    }
    Set<Long> productIdSet = projectPoList.stream().map(ProjectPo::getProductId).collect(Collectors.toSet());
    List<ProductPo> productPoList = productService.list(new ProductQo().setIdIn(productIdSet));
    if(CollectionUtils.isEmpty(projectPoList)){
      return Collections.emptyList();
    }

    List<TreeVo> treeVoList = new LinkedList<>();
    productPoList.forEach(productPo -> {
      treeVoList.add(new TreeVo(productPo.getId(), 0L, 1, productPo.getName()));
    });
    projectPoList.forEach(projectPo -> {
      treeVoList.add(new TreeVo(projectPo.getId(), projectPo.getProductId(), 2, projectPo.getName()));
    });

    return ITreeConstructor.tree(treeVoList);
  }
}
